using Abp.Application.Services.Dto;
using Abp.Domain.Entities.Auditing;
using Abp.Domain.Repositories;
using Abp.Linq.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Yozeev.BusinessLogic;
using Yozeev.BusinessLogic.Stats.Dtos;
using Yozeev.Common;
using Yozeev.Controllers.Stats.Filters;
using Yozeev.Dtos;

namespace Yozeev.Controllers.Stats
{
    /// <summary>
    /// 航线统计
    /// </summary>
    [Route("api/Stats/[Controller]/[Action]")]
    public class ScheduleController: YozeevControllerBase
    {
        private readonly IRepository<Schedule, Guid> _scheduleRep;

        private readonly IRepository<Boat, Guid> _boatRep;

        private readonly IRepository<Activity, Guid> _activityRep;

        private readonly IRepository<TicketDetail, Guid> _ticketDetailRep;

        private readonly IRepository<Route, Guid> _routeRep;

        private readonly IRepository<TicketScheduleEnable, Guid> _ticketEnableRep;

        private readonly IRepository<TicketPrice, Guid> _ticketPriceRep;

        private readonly IRepository<ActivityDetail, Guid> _activityDetail;

        private readonly AbstractFilter _routeFilter;

        private readonly AbstractFilter _boatFilter;

        private readonly AbstractFilter _ticketTypeFilter;

        private readonly IQueryHelper _queryHelper;

        public ScheduleController(IRepository<Schedule, Guid> scheduleRep,
            IRepository<Boat, Guid> boatRep, IRepository<Activity, Guid> activityRep,
            IQueryHelper queryHelper, IRepository<Route, Guid> routeRep,
            IRepository<TicketScheduleEnable, Guid> ticketEnableRep,
            IRepository<TicketPrice, Guid> ticketPriceRep,
            IRepository<ActivityDetail, Guid> activityDetail,
            RouteFilter routeFilter,
            TicketTypeFilter ticketTypeFilter,
            BoatFilter boatFilter,
            IRepository<TicketDetail, Guid> ticketDetailRep)
        {
            _ticketDetailRep = ticketDetailRep;
            _scheduleRep = scheduleRep;
            _boatRep = boatRep;
            _activityRep = activityRep;
            _routeRep = routeRep;
            _ticketEnableRep = ticketEnableRep;
            _queryHelper = queryHelper;
            _ticketPriceRep = ticketPriceRep;
            _activityDetail = activityDetail;
            _routeFilter = routeFilter;
            _ticketTypeFilter = ticketTypeFilter;
            _boatFilter = boatFilter;
        }

        /// <summary>
        /// 航线统计
        /// </summary>
        [HttpPost]
        public async Task<StatsPagedResultDto<ScheduleResultDto>> GetPagedStat(GetScheduleReportInput input, string routeId, string boatId, string ticketId)
        {
            var schedules = _scheduleRep.GetAll().Where(_queryHelper.WhereExp<Schedule>(input.queryData));
            var activities = _activityRep.GetAll();
            var routes = _routeRep.GetAll();
            if (!string.IsNullOrEmpty(routeId))
            {
                var scheduleIds = _scheduleRep.GetAll().Where(s => s.RouteId.ToString()
                .Equals(routeId)).Select(s => s.Id).ToList();
                activities = activities.Where(a => scheduleIds.Contains(a.ScheduleId.Value));
            }

            if (!string.IsNullOrEmpty(boatId))
            {
                var scheduleIds = _scheduleRep.GetAll().Where(s => s.BoatId.ToString()
                .Equals(boatId)).Select(s => s.Id).ToList();
                activities = activities.Where(a => scheduleIds.Contains(a.ScheduleId.Value));
            }

            if (!string.IsNullOrEmpty(ticketId))
            {
                var ticketPriceIds = _ticketPriceRep.GetAll()
                    .Where(t => t.TicketId.ToString().Equals(ticketId)).Select(t => t.Id).ToList();
                var activityIds = _activityDetail.GetAll()
                    .Where(a => ticketPriceIds.Contains(a.TicketPriceId))
                    .Select(a => a.ActivityId)
                    .ToList();
                activities = activities.Where(a => activityIds.Contains(a.Id));
            }
            //航线订单信息
            var acts = from activity in activities
                       where activity.PayStatus == PayStatusEnum.PayStatusPayment || activity.PayStatus == PayStatusEnum.PayStatusRefund
                       join schedule in schedules
                       on activity.ScheduleId equals schedule.Id
                       group activity by new { RouteId = schedule.RouteId } into a
                       select new
                       {
                           RouteId = a.Key.RouteId,
                           SaleAmount = a.Sum(acitivity => acitivity.ActivityType == ActivityTypeEnum.ActivityTypePayment ? acitivity.TotalAmount : 0),
                           RefundAmount = a.Sum(acitivity => acitivity.ActivityType == ActivityTypeEnum.ActivityTypeRefund ? acitivity.TotalAmount : 0),
                           TotalAmount = a.Sum(activity => activity.TotalAmount),
                           SaleCount = a.Sum(acitivity => acitivity.ActivityType == ActivityTypeEnum.ActivityTypePayment ? acitivity.TotalQuantity : 0),
                           RefundCount = a.Sum(acitivity => acitivity.ActivityType == ActivityTypeEnum.ActivityTypeRefund ? acitivity.TotalQuantity : 0),
                           TotalCount = a.Sum(activity => activity.ActivityType == ActivityTypeEnum.ActivityTypePayment ? activity.TotalQuantity : 0) -
                             a.Sum(activity => activity.ActivityType == ActivityTypeEnum.ActivityTypeRefund ? activity.TotalQuantity : 0)

                       };

            //航线信息
            var shls = from route in routes
                       join schedule in schedules
                       on route.Id equals schedule.RouteId
                       group schedule by new
                       { 
                           schedule.RouteId, 
                           schedule.Id,
                           route.RouteName,
                           route.LineInfo, 
                           route.LineImage
                       } into s
                       select new
                       {
                           RouteId = s.Key.RouteId,
                           RouteName = s.Key.RouteName,
                           ScheduleId = s.Key.Id,
                           LineInfo = s.Key.LineInfo,
                           BoatCount = s.Count(),
                           LineImage = s.Key.LineImage
                       };


            var result = from shl in shls
                         join act in acts
                         on shl.RouteId equals act.RouteId
                         select new ScheduleResultDto
                         {
                             Boats = (from boat in _boatRep.GetAll()
                                      join boatIds in  (from schedule in schedules
                                            where schedule.Id == shl.ScheduleId 
                                            && schedule.RouteId == shl.RouteId
                                            select schedule.BoatId
                                            )
                                      on boat.Id equals boatIds
                                      group boat by new { boat.BoatName, boat.Id} into g
                                     select new BoatInfo { BoatName = g.Key.BoatName, Count = g.Count() }).ToList(),
                             //Boats = (from boat in _boatRep.GetAll() select new BoatInfo { BoatName = boat.BoatName, Count = 50 }).ToList(),
                             Route = (from route in routes where route.Id == shl.RouteId select route).FirstOrDefault(),
                             BoatCount = shl.BoatCount,
                             SaleCount = act.SaleCount,
                             RefundCount = act.RefundCount,
                             TotalCount = act.TotalCount,
                             SaleAmount = act.SaleAmount,
                             RefundAmount = act.RefundAmount,
                             TotalAmount = act.TotalAmount
                         };

            var count = result.Count();
            Dictionary<string, IEnumerable<object>> filters = new Dictionary<string, IEnumerable<object>>();
            _boatFilter.Decorate(filters);
            _ticketTypeFilter.Decorate(filters);
            _routeFilter.Decorate(filters);
            return new StatsPagedResultDto<ScheduleResultDto>(count, result.AsQueryable().PageBy(input).ToList(), filters);
        }

        /// <summary>
        /// 航线统计——详情
        /// </summary>
        [HttpPost]
        public async Task<StatsPagedResultDto<ScheduleDetailResultDto>> ScheduleDetailStat(string routeId)
        {
            var schedules = _scheduleRep.GetAll().Where(sch => sch.RouteId.ToString() == routeId);
            var routes = _routeRep.GetAll();

            var result = from schedule in schedules
                         select new ScheduleDetailResultDto
                         {
                             ScheduleId = schedule.Id,
                             ScheduleCode = schedule.ScheduleCode,
                             ScheduleStatus = schedule.ScheduleStatus,
                             SaleDate = schedule.SaleDate,
                             SeatQuantity = schedule.SeatQuantity,
                             SurplusQuantity = schedule.SurplusQuantity,
                             StartTime = schedule.StartTime,
                             AuditStatus = schedule.AuditStatus,
                             EndTime = schedule.EndTime,
                             CheckStartTime = schedule.CheckStartTime,
                             CheckEndTime = schedule.CheckEndTime,
                             ReserveQuantity = schedule.ReserveQuantity,
                             Route = (from route in routes where route.Id == schedule.RouteId select route).FirstOrDefault(),
                             Boat = schedule.Boat,
                             Tickets = (from ticketEnable in _ticketEnableRep.GetAll()
                                       join sch in schedules
                                       on ticketEnable.ScheduleId equals sch.Id
                                       select ticketEnable.TicketPrice.Ticket).ToList(),                             
                             SaledCount = schedule.SeatQuantity - schedule.ReserveQuantity
                         };

            var count = result.Count();

            return new StatsPagedResultDto<ScheduleDetailResultDto>(count, result.ToList());
        }
    }
}
